package com.bifang.module.file.core.util;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.*;
import cn.hutool.extra.servlet.ServletUtil;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.S3Object;
import com.bifang.engine.assistant.core.enums.BoolEnum;
import com.bifang.engine.assistant.core.exception.AppException;
import com.bifang.module.file.common.enums.ShowFileEnum;
import com.bifang.module.file.common.util.ContentType;
import com.bifang.module.file.common.vo.FileClassVO;
import com.bifang.module.file.common.vo.FileInfoVO;
import com.bifang.module.file.common.util.Encode;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.UnsupportedCharsetException;

@Component
public class MobilServiceUtil {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private FileCommonUtil fileCommonUtil;

    @Value("${10086.obs.endpoint}")
    private String hostname;
    @Value("${10086.obs.accessKey}")
    private String accessKey;
    @Value("${10086.obs.secretKey}")
    private String secretKey;

    //---

    public Boolean upload(MultipartFile file, FileClassVO fileClassVO, FileInfoVO fileInfoVO){
        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
            return this.upload(inputStream, fileClassVO, fileInfoVO);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public Boolean upload(File file, FileClassVO fileClassVO, FileInfoVO fileInfoVO) {
        InputStream inputStream = null;
        try {
            inputStream = FileUtil.getInputStream(file);
            return this.upload(inputStream, fileClassVO, fileInfoVO);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public Boolean upload(byte[] file, FileClassVO fileClassVO, FileInfoVO fileInfoVO) {
        return this.upload(new ByteArrayInputStream(file), fileClassVO, fileInfoVO);
    }

    public Boolean upload(InputStream in, FileClassVO fileClassVO, FileInfoVO fileInfoVO){
        Boolean flag=true;
        if (fileClassVO == null) {
            throw new AppException("文件分类信息不能为空");
        }
        if (fileInfoVO == null) {
            throw new AppException("文件信息不能为空");
        }
        fileCommonUtil.initFile(in, fileClassVO, fileInfoVO);
        // 校验文件是否可以上传
        fileCommonUtil.checkFile(fileInfoVO.getFileSuffix(), fileInfoVO.getFileSize(), fileClassVO);
        if (StringUtils.isNotBlank(fileInfoVO.getEncryptionFlag())) {
            if (BoolEnum.TRUE.getType().endsWith(fileInfoVO.getEncryptionFlag())) {
                String fileName = this.getFileName(fileInfoVO);
                File file = fileCommonUtil.createTempFile(in, fileName);
                fileInfoVO.setFilePassowrd(RandomUtil.randomString(5));
                new Encode(true, file, fileInfoVO.getFilePassowrd()).run();
                InputStream inputStream = null;
                try {
                    inputStream = FileUtil.getInputStream(file);
                    flag = uploadFile(inputStream, fileClassVO, fileInfoVO);
                } catch (Exception e) {
                    e.printStackTrace();
                    flag = false;
                } finally {
                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                fileCommonUtil.delTempFile(file);
                return flag;
            }
        } else {
            fileInfoVO.setEncryptionFlag(BoolEnum.FALSE.getType());
        }
        flag = uploadFile(in, fileClassVO, fileInfoVO);

        return flag;
    }
    public Boolean uploadFile(InputStream in, FileClassVO fileClassVO, FileInfoVO fileInfoVO) {
        String bucketName = fileInfoVO.getStorageGroup();
        String objectKey = IdUtil.fastSimpleUUID() + "." + fileInfoVO.getFileSuffix();;
        String fileClassPath = fileInfoVO.getFileClassPath();

        Boolean flag = true;

        ClientConfiguration opts = new ClientConfiguration();
        opts.setSignerOverride("S3SignerType");
        AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
        AmazonS3Client client = new AmazonS3Client(credentials, opts);
        client.setEndpoint(hostname);

        String path = fileCommonUtil.getPath("", fileClassPath, objectKey);
        try   {
            client.putObject(bucketName, path, in, null);
        } catch (Exception e) {
            logger.error("文件上传失败", e);
            flag = false;
        }
        client.shutdown();

        fileInfoVO.setFilePath(path);
        return flag;
    }


    private String getFileName(FileInfoVO fileInfoVO) {
        return fileInfoVO.getFileMd5() + "." + fileInfoVO.getFileSuffix();
    }

    /** 文件下载直接输出返回流 */
    public void download(FileInfoVO fileInfoVO, HttpServletResponse response) {
        String bucketName = fileInfoVO.getStorageGroup();//桶
        if (StringUtils.isBlank(bucketName)) {
            bucketName = "xpd2";
        }
        String objectKey = fileInfoVO.getFilePath();//云上的文件目录


        ClientConfiguration opts = new ClientConfiguration();
        opts.setSignerOverride("S3SignerType");
        AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
        AmazonS3Client client = new AmazonS3Client(credentials, opts);
        client.setEndpoint(hostname);

        boolean exists = client.doesObjectExist(bucketName, objectKey);

        if (!exists) {
            throw new AppException("文件不存在");
        }

        S3Object s3Object=null;
        try {

            // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
            s3Object = client.getObject(bucketName, objectKey);

            InputStream in = s3Object.getObjectContent();
            String fileName = StringUtils.isNotBlank(fileInfoVO.getFileName()) ?
                    URLEncoder.encode(fileInfoVO.getFileName(), "utf-8")
                            .replaceAll("%20", "\\+")
                            .replaceAll("%28", "\\(")
                            .replaceAll("%29", "\\)")
                            .replaceAll("%3B", ";")
                            .replaceAll("%40", "@")
                            .replaceAll("%23", "\\#")
                            .replaceAll("%26", "\\&")
                            .replaceAll("%2C", "\\,")
                            .replaceAll("%24", "\\$")
                            .replaceAll("%25", "\\%")
                            .replaceAll("%5E", "\\^")
                            .replaceAll("%3D", "\\=")
                            .replaceAll("%2B", "\\+") : fileInfoVO.getFileMd5() + "." + fileInfoVO.getFileSuffix();
            String contentType = ContentType.getContentType("." + fileInfoVO.getFileSuffix());
            if (contentType == null) {
                contentType = ContentType.getContentType(fileInfoVO.getFileSuffix());
            }
            response.setCharacterEncoding("utf-8");
            response.setContentType(contentType);
            response.addHeader("Content-Length", "" + fileInfoVO.getFileSize());
            if (ShowFileEnum.getByType(contentType) != null) {
                final String charset = ObjectUtil.defaultIfNull(response.getCharacterEncoding(), CharsetUtil.UTF_8);
                response.setHeader("Content-Disposition", StrUtil.format("inline;filename=\"{}\"",
                        URLUtil.encode(fileName, CharsetUtil.charset(charset))));
            } else {
                response.setContentType("application/octet-stream;charset=utf-8");
                final String charset = ObjectUtil.defaultIfNull(response.getCharacterEncoding(), CharsetUtil.UTF_8);
                response.setHeader("Content-Disposition", StrUtil.format("attachment;filename=\"{}\"",
                        URLUtil.encode(fileName, CharsetUtil.charset(charset))));
            }
            response.setContentLengthLong(fileInfoVO.getFileSize());


            ServletUtil.write(response, in);
        } catch (AmazonServiceException e) {
            throw e;
        }  catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (UnsupportedCharsetException e) {
            throw e;
        } finally {
            if (s3Object != null) {
                try {
                    s3Object.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (s3Object != null) {
                client.shutdown();
            }
        }
    }

    /** 文件下载 输出到指定路径 */
    public void download(FileInfoVO fileInfoVO, String filePath) {
        File file = FileUtil.touch(filePath);
        this.download(fileInfoVO, file);
    }

    /** 文件下载 输出到指定文件 */
    public void download(FileInfoVO fileInfoVO, File file) {
        String bucketName = fileInfoVO.getStorageGroup();//桶
        if (StringUtils.isBlank(bucketName)) {
            bucketName = "xpd2";
        }
        String objectKey = fileInfoVO.getFilePath();//云上的文件目录


        ClientConfiguration opts = new ClientConfiguration();
        opts.setSignerOverride("S3SignerType");
        AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
        AmazonS3Client client = new AmazonS3Client(credentials, opts);
        client.setEndpoint(hostname);

        boolean exists = client.doesObjectExist(bucketName, objectKey);
        if (!exists) {
            throw new AppException("文件不存在");
        }

        S3Object s3Object=null;
        InputStream in = null;
        try {
            // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
            s3Object = client.getObject(bucketName, objectKey);
            in = s3Object.getObjectContent();
            FileUtil.writeFromStream(in, file);
            if (BoolEnum.TRUE.getType().equals(fileInfoVO.getEncryptionFlag())) {
                new Encode(false, file, fileInfoVO.getFilePassowrd()).run();
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (s3Object != null) {
                try {
                    s3Object.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (client != null) {
                client.shutdown();
            }
        }
    }

    /** 根据key删除OSS服务器上的文件 */
    public void deleteFile(FileInfoVO fileInfoVO) {
        String bucketName = fileInfoVO.getStorageGroup();//桶
        if (StringUtils.isBlank(bucketName)) {
            bucketName = "xpd2";
        }
        ClientConfiguration opts = new ClientConfiguration();
        opts.setSignerOverride("S3SignerType");
        AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
        AmazonS3Client client = new AmazonS3Client(credentials, opts);
        client.setEndpoint(hostname);
        String objectKey = fileInfoVO.getFilePath();//云上的文件目录

        client.deleteObject(bucketName, objectKey);
        logger.info("删除" + bucketName + "下的文件" + objectKey + "成功");
    }

    /** 获取base64文件 */
    public String getBase64(FileInfoVO fileInfoVO) {
        fileCommonUtil.checkBase64(fileInfoVO.getFileSize());
        String fileName = fileInfoVO.getFileMd5() + "." + fileInfoVO.getFileSuffix();
        if (fileInfoVO.getForceFlag()) {
            fileCommonUtil.delTempFileDownloadByName(fileName);
        }
        File file = fileCommonUtil.createTempFileDownload(fileName);
        if (file.length() <= 0) {
            // 空文件重新下载
            this.download(fileInfoVO, file);
            if (BoolEnum.TRUE.getType().equals(fileInfoVO.getEncryptionFlag())) {
                new Encode(false, file, fileInfoVO.getFilePassowrd()).run();
            }
        }
        String base64 = Base64.encode(file);
        FileUtil.del(file);
        return base64;
    }

}